import re
import os
import sys, codecs

class Propertier:
    """Class for setting properties in PHP code"""
    _directory = ''
    _types = []
    _staticProperites = {}

    def __init__(self, directory, types=[], staticProperites = {}):
        """Contructor
        directory - direcotory to scan
        types - name of variable containing elements (like uses, components)
        """
        self._directory = directory;
        self.set_types(types)
        self._staticProperites = staticProperites
        
    def set_types(self, types):
        """Just a setter"""
        self._types = types

    def get_elements(self, type, text, postfix = ''):
        """Extract elements for 'type' variable
        text - code
        postfix - optional postfix added to extracted class name
        """
        if re.search('\$' + type + '\s*\=\s*array\((.*?)\);', text, flags=re.DOTALL):
            tmp = re.findall('\$' + type + '\s*\=\s*array\((.*?)\);', text, flags=re.DOTALL)[0].replace('\'', '').replace('"', '')
            p = re.compile('\s*\=\>\s*array\((.*?)\)',  flags=re.DOTALL)
            tmp = p.sub('', tmp)
            tmpList = tmp.split(',')
            tmpList = [x.strip() for x in tmpList if re.search("^\w+$", x.strip())]
            return dict([(str, str+postfix) for str in tmpList])
        else:
            return dict()

    def insert_properties(self, lines):
        """Insert properites to code"""
        if not re.match("^\<\?php", lines[0]):
            print('Not a php file!')
            exit

        state = 0 #0 begin, 1 comments, 2 class
        className = '';
        properties = dict()
        fileHasComments = 0
        missingStaticProperites = len(self._staticProperites.keys())
        
        for line in lines:
            if state == 0:
                if re.match('\s*\/\*\*', line):
                    state = 1
                    fileHasComments = 1
                if re.match('\s*class \w', line):
                    className = re.findall('\s*class (\w*)', line)
                    break
            elif state == 1:
                if re.match('\s*\*\/', line):
                    break
                elif re.match('\s*\*\s*\@property \w* \$\w*', line):
                    tmp = re.findall('[ \t]*\*\s*\@property (\w*) \$(\w*)', line)[0]
                    
                    properties[tmp[0]] = tmp[1];
                elif missingStaticProperites > 0:
                    for prop in self._staticProperites.keys():
                        if re.match('\s*\*\s*\@'+prop+' \w*', line):
                            missingStaticProperites = missingStaticProperites - 1


        text = "".join(lines)
        oldLen = len(properties)

        for var_type in self._types:
            if isinstance(var_type, str):
                properties.update(self.get_elements(var_type, text))
            else:
                properties.update(self.get_elements(var_type[0], text, var_type[1]))
        
        
        if len(properties) > oldLen or missingStaticProperites > 0:
            #remove old @property tags
            
            text = re.sub(' *\*\s*\@property .*\n', '', text)
            #remove old staticProperty tags
            for prop in self._staticProperites:
                text = re.sub(' *\*\s*\@' + prop + '.*\n', '', text)
            string = ''

            for prop,value in self._staticProperites.items():
                string += ' * @' + prop + ' ' + value + '\n'


            for prop in sorted(properties.keys()):
                string += ' * @property ' + properties[prop] + ' $' + prop + '\n'
            
            if fileHasComments:
                text = text.replace(' */', string + ' */', 1)
            else:
                text = text.replace('<?php', '<?php\n/**\n *\n' + string + ' */', 1)
            return text
        else:
            return ''


    def read_file(self, file):
        """Read file content and add properties"""
        if file.find('.php') != -1:
            f = codecs.open(self._directory + file, mode = 'r', encoding='utf-8')
            text = self.insert_properties(f.readlines())
            f.close();
            if text != '':
                f = codecs.open(self._directory + file,  mode = 'w', encoding='utf-8')
                f.write(text)
                print(self._directory + file + ' updated!')
                f.close()

    def read_dir(self):
        """Read files in directory"""
        files = os.listdir(self._directory)
        for file in files:
            self.read_file(file)



def main():

    print('start')


    if len(sys.argv) > 1 and sys.argv[1].find('.php') != -1:
            p = Propertier('./', ['uses', {'components': 'Component'}])
            p.read_file(sys.argv[1])
    else:
        if len(sys.argv) > 1:
            dir = sys.argv[1] + '/'
        else:
            dir = './'

        p = Propertier(dir, ['uses', ('components', 'Component')], {'package' : 'test'})
        p.read_dir()




if __name__ == "__main__":
    main()
